/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2010 huliqing, huliqing.cn@gmail.com
 *
 * This file is part of QFaces.
 * QFaces is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * QFaces is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with QFaces.  If not, see <http://www.gnu.org/licenses/>.
 *
 * 这个文件是QFaces的一部分。
 * 您可以单独使用或分发这个文件，但请不要移除这个头部声明信息.
 * QFaces是一个自由软件，您可以自由分发、修改其中的源代码或者重新发布它，
 * 新的任何修改后的重新发布版必须同样在遵守LGPL3或更后续的版本协议下发布.
 * 关于LGPL协议的细则请参考COPYING、COPYING.LESSER文件，
 * 您可以在QFaces的相关目录中获得LGPL协议的副本，
 * 如果没有找到，请连接到 http://www.gnu.org/licenses/ 查看并获取副本。
 *
 * - Author: Huliqing
 * - Contact: huliqing.cn@gmail.com
 * - License: GNU Lesser General Public License (LGPL)
 * - Blog and source code availability: http://www.huliqing.name/
 */

Q.F.UIInputHelp = {
    init : function(ID_CLIENT,ID_PANEL,listenerExp,componentClass,_for,ref,title,header,footer,styleClass,styleSelectedClass,rowClasses,columnClasses,headerClass,footerClass,titleClass,onSelect,selectIndex,delay,autoClose) {
        var inputHelp = new Q.F.UIInputHelp.InputHelp(ID_CLIENT,ID_PANEL,listenerExp,componentClass,_for,ref,title,header,footer,styleClass,styleSelectedClass,rowClasses,columnClasses,headerClass,footerClass,titleClass,onSelect,selectIndex,delay,autoClose);
        Q.F.put(ID_CLIENT, inputHelp);
    }
}
Q.F.UIInputHelp.InputHelp = function(ID_CLIENT,ID_PANEL,listenerExp,componentClass,_for,ref,title,header,footer,styleClass,styleSelectedClass,rowClasses,columnClasses,headerClass,footerClass,titleClass,onSelect,selectIndex,delay,autoClose) {
    this.ID_CLIENT = ID_CLIENT;
    this.panel = Q.get(ID_PANEL); // Include DataPanel
    this.listenerExp = listenerExp;
    this.componentClass = componentClass;
    this._for = _for;
    this.target; // for 属性所指定的目标组件
    this.refArr = (ref == "" ? new Array() : ref.split(","));
    this.titleArr = (title == "" ? new Array() : title.split(","));
    this.header = header;
    this.footer = footer;
    this.styleClass = styleClass;
    this.styleSelectedClass = styleSelectedClass;
    this.rowClassesArr = (rowClasses == "" ? new Array() : rowClasses.split(","));
    this.columnClassesArr = (columnClasses == "" ? new Array() : columnClasses.split(","));
    this.headerClass = headerClass;
    this.footerClass = footerClass;
    this.titleClass = titleClass;
    this.onSelect = new Function(onSelect);
    this.selectIndex = parseInt(selectIndex, 10);
    this.delay = parseInt(delay, 10);
    this.autoClose = (autoClose == "true");
	
    this.focus = false;		// 目标组件是否正获得焦点
    this.selecting = false;	// 是否正在选择值，如果正在选择值，则不应该进行ajax请求
    // target最后一次发生过ajax请求的值(只有target.value与targetLastValue不等的时候才需要Ajax请求)
    // 初始化为""(空)保证target在首次获得焦点时（未输入值）不会立即进行ajax请求
    this.targetLastValue = "";
	
    this.initTryCount = 0;	// 这个属性主要是限制init的偿试次数，因为如果_for所指定的目标组件不存在，那么init偿试一定次数之后应该放弃
    this.dataPanel;			// 参考：Q.F.UIInputHelp.DataPanel
	
    // ---------- Interface
	
    // 获取所选择的值
    this.getValue = function() {
        if (this.target) return this.target.value;
    }
	
    // ---------- init
    this.init = function(inputHelp) {
        inputHelp.initTryCount++;
        if (inputHelp.initTryCount > 100) return;
        inputHelp.target = Q.get(inputHelp._for);
        if (inputHelp.target == null) {
            Q.U.setTimeout(inputHelp.init, 50, inputHelp);
        } else {
            inputHelp.target.setAttribute("autocomplete", "off");
            inputHelp.dataPanel = new Q.F.UIInputHelp.DataPanel(inputHelp);
            inputHelp.panel.appendChild(inputHelp.dataPanel.getPanel()); // 动态数据面板
            Q.U.attachEvent(inputHelp.target, "onfocus", function() {
                return inputHelp.onfocus();
            });
            Q.U.attachEvent(inputHelp.target, "onblur", function() {
                return inputHelp.onblur();
            });
            Q.U.attachEvent(inputHelp.target, "onkeydown", function() {
                return inputHelp.onkeydown();
            });
        }
    }
    this.onfocus = function() {
        this.focus = true;
        this.loop(this)
    }
    this.onblur = function() {
        this.focus = false;
        this.dataPanel.close();
    }
    this.onkeydown = function() { // 38 -> up, 40 -> down, 37 -> left, 39 -> right
        var event = Q.U.getEvent();
        // selecting 状态可以避免将选中的值继续发送到后台请求
        this.selecting = (event.keyCode == 38 || event.keyCode == 40 || event.keyCode == 13 || event.keyCode == 37 || event.keyCode == 39);
        if (event.keyCode == 38)
            this.dataPanel.previous();
        if (event.keyCode == 40)
            this.dataPanel.next();
    }
    this.loop = function(inputHelp) {
        if (!inputHelp.focus) {
            return;
        }
        // 非"选择值"状态中以及最新输入的值与最后一次发生的请求时的值不一样时才需要重新请求值
        if (!inputHelp.selecting && (inputHelp.target.value != inputHelp.targetLastValue)) {
            inputHelp.ajaxInvoke();
        }
        Q.U.setTimeout(inputHelp.loop, inputHelp.delay, inputHelp);
    }
    // -> this.targetLastValue = this.target.value;
    // -> ajax request
    this.ajaxInvoke = function(inputHelp) {
        var _self = (inputHelp ? inputHelp : this);
        var ajax = Q.F.Ajax.build(_self.ID_CLIENT);
		
        // 1.非常重要，否则会造成无限重复请求
        _self.targetLastValue = _self.target.value;
		
        // 2.请求
        ajax.put("componentClass", _self.componentClass);
        ajax.put("listenerExp", _self.listenerExp);
        ajax.put("targetValue", _self.targetLastValue)
        ajax.put("refCount", _self.refArr.length);
        for (var i = 0; i < _self.refArr.length; i++) {
            var refComponent = Q.get(_self.refArr[i]);
            if (refComponent != null) {
                ajax.put("refValue" + i, refComponent.value);
            } else {
                alert("Component not found by id=" + _self.refArr[i]);
            }
        }
        
        // 4.处理
        var process = function () {
            _self.process();
        }
	    
        // 3.发送
        ajax.setProcess(process);
        ajax.get();
    }
    this.process = function() {
        var ajax = Q.F.Ajax.find(this.ID_CLIENT);
        var xml = ajax.request.responseXML;
        if (!xml) return;
        // 获取行数,并保证能够获得数据
        var rowElements = xml.documentElement.getElementsByTagName("row");
        var rows = rowElements.length;
        if (rows <= 0) return;
        // 获取列表
        var temp = rowElements[0].getElementsByTagName("column");
        var cols = temp.length;
        if (cols <= 0) return;
        // 生成二维数组
        var rowObjs = new Array(rows);
        for (var i = 0; i < rows; i++) {
            var colObjs = new Array(cols);
            rowObjs[i] = colObjs;
            var columnElements = rowElements[i].getElementsByTagName("column");
            for (var n = 0; n < cols; n++) {
                colObjs[n] = columnElements[n].getAttribute("value");
            }
        }
        this.dataPanel.open();
        this.dataPanel.loadData(rowObjs);
    }
    this.setValue = function(value) {
        if (this.target) this.target.value = value;
    }
    this.init(this);
}
Q.F.UIInputHelp.DataPanel = function(inputHelp) {
    this.inputHelp = inputHelp;
    this.panel = null;	// 存放数据的panel
    this.headerPanel = null;
    this.footerPanel = null;
    this.data = null;	// 包含数据的Table,参考：Q.U.createTableAsObject
    this.index = 0;		// 第0行为title, 当前选中的行
    this.busy = false;	// 如果处于busy状态则不能关闭
	
    this.init = function() {
        this.panel = document.createElement("div");
        this.headerPanel = document.createElement("div");
        this.footerPanel = document.createElement("div");
        this.panel.className = this.inputHelp.styleClass;
        if (this.inputHelp.header != "") {
            this.headerPanel.innerHTML = this.inputHelp.header;
            this.headerPanel.className = this.inputHelp.headerClass;
        }
        if (this.inputHelp.footer != "") {
            this.footerPanel.innerHTML = this.inputHelp.footer;
            this.footerPanel.className = this.inputHelp.footerClass;
        }
        this.close();
    }
    this.loadData = function(rowObjs) { // 参数为一个2维数组
        var _self = this;
        var table = document.createElement("table");
        var rows = rowObjs.length + 1; // 重要：第一行为title
        var columns = rowObjs[0].length;
        this.data = Q.U.createTableAsObject(table, rows, columns);
		
        // Set title
        for (var n = 0; n < columns; n++) {
            var titleArr = _self.inputHelp.titleArr;
            if (titleArr.length > n) {
                this.data.column[0][n].innerHTML =  titleArr.length > n ? titleArr[n] : "";
                this.data.column[0][n].className = _self.inputHelp.titleClass;
            } else {
                this.data.column[0][n].style.cssText = "height:0;padding:0;margin:0;font-size:0;"; // 隐藏Title行，否则在FF下或部分其它浏览器该行为占用空间
            }
        }
		
        // Set data
        for (var i = 1; i < rows; i++) {
            for (var n = 0; n < columns; n++) {
                this.data.column[i][n].rowIndex = i;
                this.data.column[i][n].colIndex = n;
                // i是从1开始，因为0为title,但是rowObjs为返回的二维数据，是从0开始,所以必须是i-1
                this.data.column[i][n].innerHTML = rowObjs[i-1][n];
            }
        }
		
        // Set css
        for (var i = 1; i < rows; i++) {
            this.data.row[i].style.cursor = "pointer";
            if (_self.inputHelp.rowClassesArr.length > 0)
                this.data.row[i].classNameOld = this.data.row[i].className = _self.inputHelp.rowClassesArr[i % _self.inputHelp.rowClassesArr.length];
            for (var n = 0; n < columns; n++) {
                if (_self.inputHelp.columnClassesArr.length > 0)
                    this.data.column[i][n].classNameOld = this.data.column[i][n].className = _self.inputHelp.columnClassesArr[n % _self.inputHelp.columnClassesArr.length];
            }
        }
		
        // Set event
        for (var i = 1; i < rows; i++)
            this.setRowEvent(i);

        while (this.panel.hasChildNodes()) {
            this.panel.removeChild(this.panel.firstChild);
        }
        table.onmouseover = function () {
            _self.busy = true;
        } // 阻止因input失去焦点时导至dataPanel关闭
        table.onmouseout = function() {
            _self.busy = false;
        }
        table.setAttribute("border", "0");
        table.setAttribute("cellspacing", "0");
        table.setAttribute("cellpadding", "5");
        table.cellSpacing = 0; // For IE
        table.cellPadding = 5;
        this.index = 0; // 默认从第一个选择起
        this.panel.appendChild(this.headerPanel);
        this.panel.appendChild(table);
        this.panel.appendChild(this.footerPanel);
    }
    this.setRowEvent = function(rowIndex) {
        var _self = this;
        var obj = this.data.row[rowIndex];
        obj.onmouseover = function() {
            _self.setSelectedRowStyleClass(this.rowIndex);
            _self.index = this.rowIndex;
        }
        obj.onmouseout = function() {
            _self.clearRowStyleClass(this.rowIndex);
        }
        obj.onclick = function() {
            _self.inputHelp.selecting = true; // selecting = true用于阻止在选择值后，input重新focus后所引起的ajax请求
            _self.inputHelp.setValue(_self.getValue(this.rowIndex, _self.inputHelp.selectIndex));
            if (_self.inputHelp.autoClose) {
                _self.busy = false;
                _self.close();
            }
            _self.inputHelp.target.focus();
            _self.inputHelp.onSelect.apply();
        }
    }
    this.getPanel = function() {
        return this.panel;
    }
    this.getValue = function(rowIndex, colIndex) {
        if (rowIndex < 1 || rowIndex >= this.data.row.length) return "";
        if (this.data.column[0].length <= 0) return "";
        if (colIndex < 0) colIndex = 0;
        if (colIndex >= this.data.column[0].length) colIndex = this.data.column[0].length - 1;
        return this.data.column[rowIndex][colIndex].innerHTML;
    }
    this.previous = function() { // 选择上一行
        this.clearRowStyleClass(this.index);
        this.index--;
        if (this.index < 1) this.index = 1;
        this.setSelectedRowStyleClass(this.index);	// 设置选中行样式
        this.inputHelp.setValue(this.getValue(this.index, this.inputHelp.selectIndex));
    }
    this.next = function() { // 选择下一行
        this.clearRowStyleClass(this.index);
        this.index++;
        if (this.index >= this.data.row.length) this.index = this.data.row.length - 1;
        this.setSelectedRowStyleClass(this.index);
        this.inputHelp.setValue(this.getValue(this.index, this.inputHelp.selectIndex));
    }
    // 设置某一row为选中的样式
    this.setSelectedRowStyleClass = function(rowIndex) {
        this.clearRowStyleClass(this.index);
        if (rowIndex >= 1 && rowIndex < this.data.row.length) {
            for (var n = 0; n < this.data.column[0].length; n++) {
                this.setColumnStyleClass(rowIndex, n, this.inputHelp.styleSelectedClass);
            }
        }
    }
    // 清除某一行的样式（还原为原始设置）
    this.clearRowStyleClass = function(rowIndex) {
        if (rowIndex >= 1 && rowIndex < this.data.row.length) {
            for (var n = 0; n < this.data.column[0].length; n++) {
                this.setColumnStyleClass(rowIndex, n, this.data.column[rowIndex][n].classNameOld);
            }
        }
    }
    // 设置某一row的样式
    this.setColumnStyleClass = function(rowIndex, colIndex, className) {
        if (rowIndex >=1 && rowIndex < this.data.row.length) {
            if (colIndex >= 0 && colIndex < this.data.column[0].length) {
                this.data.column[rowIndex][colIndex].className = className;
            }
        }
    }
    this.open = function() {
        this.panel.style.display = "block";
    }
    this.close = function() {
        if (this.busy) return;
        this.panel.style.display = "none";
    }
    this.init();
}

